/*
 *             Copyright (C) 2024 Steve Jrong
 * 
 * 	   GitHub Homepage: https://www.github.com/SteveJrong
 *      Gitee Homepage: https://gitee.com/stevejrong1024
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.stevejrong.waiter.unique.id.component.generator;

import java.time.Duration;

import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RAtomicLongReactive;
import org.springframework.stereotype.Component;

import com.stevejrong.waiter.common.component.BaseConstants;
import com.stevejrong.waiter.common.component.util.DateTimeUtil;
import com.stevejrong.waiter.common.component.util.RandomUtil;
import com.stevejrong.waiter.unique.id.component.common.CacheKeyTypeEnum;
import com.stevejrong.waiter.unique.id.component.util.RedissonUtil;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;

/**
 * 工具类 - 网络请求全局唯一ID生成器
 * 
 * @author Steve Jrong
 * @since 1.0
 */
@Component
@Slf4j
public final class RequestIdGenerator {

	/**
	 * 生成用于网络请求的全局唯一ID（20位纯数字）
	 * <p>
	 * 这是一个异步方法。
	 * <p>
	 * 1天过期并重设。
	 * <p>
	 * 生成规则：
	 * <ol>
	 * <li>按照以下元素生成。参与的元素如下：
	 * <ul>
	 * <li>当前日期（6位数，左侧不足补零）。</li>
	 * <li>自增数（10位数，左侧不足补零）。</li>
	 * <li>随机数（4位数，左侧不足补零）。</li>
	 * </ul>
	 * </li>
	 * <li>总体反向，得出最终的全局唯一ID。</li>
	 * </ol>
	 *
	 * @return 20位数纯数字的用于网络请求的全局唯一ID
	 */
	public Mono<String> generate() {
		// 当前日期字符串
		String currentDateString = DateTimeUtil.formatDate(BaseConstants.DateTimeConstants.FMT_YYMMDD_WITHOUT_ANY_SEPARATOR.desc(),
				BaseConstants.DateTimeConstants.UTC_GMT8_ZONE_ID.desc(), DateTimeUtil.getDateByNow());
		
		// 从Redis取得一个自增值
		Mono<Long> incrValueStream = Mono.defer(() -> {
			RAtomicLongReactive longReactive = RedissonUtil.getClient().getAtomicLong(CacheKeyTypeEnum.REQUEST_ID.desc()
					+ DateTimeUtil.formatDate(BaseConstants.DateTimeConstants.FMT_YYMMDD_WITHOUT_ANY_SEPARATOR.desc(), BaseConstants.DateTimeConstants.UTC_GMT8_ZONE_ID.desc(), DateTimeUtil.getDateByNow()));
			longReactive.expire(Duration.ofDays(1)).subscribe();
			
			return longReactive.incrementAndGet();
		});
		
		// 本地生成一个随机数
		Mono<Integer> randomValueStream = RandomUtil.generateRandomValue(1000, 9999);
		
		// 等待上述2个数据都产生以后，执行以下整合逻辑
		return Mono.zip(incrValueStream, randomValueStream).flatMap(data -> {
			Long incrValue = data.getT1();
			Integer randomValue = data.getT2();
			
			return Mono.just(
					StringUtils.reverse(currentDateString
							+ StringUtils.leftPad(incrValue.toString(), 10, "0")
							+ StringUtils.leftPad(randomValue.toString(), 4, "0"))
					);
		});
	}
}
